package net.wang.cloud.order.service;


import lombok.extern.slf4j.Slf4j;
import net.wang.cloud.dto.IOrderService;
import net.wang.cloud.dto.OrderDTO;
import net.wang.cloud.order.domain.Order;
import net.wang.cloud.order.repo.OrderRepo;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@Service
@Slf4j
public class OrderService implements IOrderService {

    @Resource
    private OrderRepo orderRepo;
    @Resource
    private JmsTemplate jmsTemplate;


    @Override
    public OrderDTO getOrder(Long id) {
        Order order = orderRepo.findOne(id);
        log.info("order : {}", order);
        OrderDTO orderDTO = new OrderDTO();
        orderDTO.setId(order.getId());
        orderDTO.setAmount(order.getAmount());
        orderDTO.setStoreName(order.getStoreName());
        orderDTO.setCreateAt(order.getCreateAt());
        return orderDTO;
    }


    public List<Order> all() {
        return orderRepo.findAll();
    }


    /**
     * 创建新订单，向order:new 发送订单信息，由 net.wang.cloud.ticket.service.TicketService#handleTicket监听
     *
     * @param orderDTO
     */
    public void createOrder(OrderDTO orderDTO) {
        orderDTO.setUuid(String.valueOf(UUID.randomUUID()));
        log.info("create order {}", orderDTO);
        jmsTemplate.convertAndSend("order:new", orderDTO);
    }

    @Transactional
    @JmsListener(destination = "order:lock", containerFactory = "jmsListenerContainerFactory")
    public void handleOrderAfterTicketLocked(OrderDTO orderDTO) {
        log.info("order lock : {}", orderDTO);
        Order order = orderRepo.findByUuid(orderDTO.getUuid());
        if (order != null) {
            log.info("MSG ALREADY PROCESSED ");
        } else {
            orderDTO.setStatus("NEW");
            Order save = orderRepo.save(build(orderDTO));
            log.info("=== order new save ===  order : {}", save);
            orderDTO.setId(save.getId());
        }
        jmsTemplate.convertAndSend("order:pay", orderDTO);
    }

    @Transactional
    @JmsListener(destination = "order:finish", containerFactory = "jmsListenerContainerFactory")
    public void handleOrderFinished(OrderDTO orderDTO) {
        log.info("order finish: {}", orderDTO);

        Order order = orderRepo.findOne(orderDTO.getId());
        order.setStatus("FINISH");
        orderRepo.save(order);

    }

    /**
     * 订单失败
     * 1、锁票失败，ticket服务出现问题，消息没有处理时出现的问题
     * net.wang.cloud.ticket.service.TicketService#handleTicket(net.wang.cloud.dto.OrderDTO)中锁票失败，没有创建新订单，orderDTO的ID为空
     * 2、扣费失败
     * 3、定时任务检查订单超时
     *
     * @param orderDTO
     */
    @Transactional
    @JmsListener(destination = "order:fail", containerFactory = "jmsListenerContainerFactory")
    public void handleOrderFail(OrderDTO orderDTO) {
        log.info("order fail: {}", orderDTO);
        Order order;
        orderDTO.setStatus("FAIL");
        if (orderDTO.getId() == null || orderDTO.getId() == 0) {
            orderDTO.setReason("TICKET_LOCK_FAIL");
            order = build(orderDTO);
        } else {
            order = orderRepo.findByUuid(orderDTO.getUuid());
            order.setStatus("FAIL");
            if (orderDTO.getReason().equalsIgnoreCase("NOT_ENOUGH_DEPOSIT")) {
                order.setReason("NOT_ENOUGH_DEPOSIT");
            } else if (orderDTO.getReason().equalsIgnoreCase("TIMEOUT")) {
                order.setReason("TIMEOUT");
            } else {
                log.error("UNKNOWN REASON !");
            }
        }
        orderRepo.save(order);
    }


    private Order build(OrderDTO orderDTO) {
        Order order = new Order();
        order.setUuid(orderDTO.getUuid());
        order.setCustomerId(orderDTO.getCustomerId());
        order.setTicketNumber(orderDTO.getTicketNumber());
        order.setStatus(orderDTO.getStatus());
        order.setReason(orderDTO.getReason());
        order.setStoreName(orderDTO.getStoreName());
        order.setAmount(orderDTO.getAmount());
        order.setCreateAt(new Date());

        return order;
    }


    @Scheduled(fixedDelay = 10000L)
    public void checkTimeOutOrders() {
        ZonedDateTime checkTime = ZonedDateTime.now().minusMinutes(1L);

        List<Order> orders = orderRepo.findByStatusAndCreateAtBefore("NEW", checkTime);

        orders.forEach(order -> {
            log.warn("ORDER TIMEOUT order : {}", order);
            OrderDTO orderDTO = new OrderDTO();
            orderDTO.setId(order.getId());
            orderDTO.setTicketNumber(order.getTicketNumber());
            orderDTO.setUuid(order.getUuid());
            orderDTO.setAmount(order.getAmount());
            orderDTO.setStoreName(order.getStoreName());
            orderDTO.setCustomerId(order.getCustomerId());
            orderDTO.setReason("TIMEOUT");
            jmsTemplate.convertAndSend("order:fail", orderDTO);
        });
    }
}
